/*

MGC	Maze Game Compiler

(C) 24/8/88  A.Key

*/

#include <stdio.h>
#include <ctype.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include "standard.h"

char	progname [] = "mgc";
static char sccs_id [] = "@(#)Maze Game Compiler  3/9/92";

/*...sfatal:0:*/
static void fatal(const char *fmt, ...)
	{
	va_list	vars;
	char	s [256+1];

	va_start(vars, fmt);
	vsprintf(s, fmt, vars);
	va_end(vars);
	fprintf(stderr, "%s: %s\n", progname, s);
	exit(1);
	}
/*...e*/
/*...susage:0:*/
static void usage(void)
	{
	fprintf(stderr, "usage: %s filename\n", progname);
	exit(1);
	}
/*...e*/

#define	LINELEN	240
#define	FN_LEN	80

static char fn [FN_LEN+1];
static FILE *fp;

static void trunc(char *base)
	{
	char *dot, *slash;

	if ( (dot = strrchr(base, '.')) != NULL )
		if ( (slash = strrchr(base, '\\')) == NULL || slash < dot )
			*dot = '\0';
	}

static char *suffix(char *fn, char *base, char *ext)
	{
	strcpy(fn, base);
	strcat(fn, ".");
	return ( strcat(fn, ext) );
	}

static int line_no = 0;
static char line [LINELEN+1];

static BOOLEAN get_line(void)
	{
	int len;

	do
		{
		line_no++;
		if ( fgets(line, LINELEN+1, stdin) == NULL )
			return ( FALSE );
		}
	while ( *line == ';' );

	if ( (len = strlen(line)) && line [len - 1] == '\n' )
		line [len - 1] = '\0';

	return ( TRUE );
	}

static char block [76][77];

static void read_in_block(void)
	{
	int i;

	for ( i = 0; i < 76; i++ )
		if ( get_line() )
			strcpy(block [75 - i], line);
		else
			fatal("incomplete block definition at line %d", line_no);
	}

/*
Data that is unique to a screen.
*/

#define	BT_MAX		5

typedef struct scn_struct
	{
	BOOLEAN	scn_visited;
	int	scn_palette;
	int	scn_n_bastards [BT_MAX];
	} SCN;

#define	SCN_ARRAY_X_SZ	12
#define	SCN_ARRAY_Z_SZ	12

static SCN scns [SCN_ARRAY_X_SZ][SCN_ARRAY_Z_SZ];


#define	SQR_PER_SCN	5		/* SQRS per SCN (both x & z)         */

#define	T_VISIBLE	0x0001		/* is it visible as a surface        */
#define	T_MINUS		0x0002		/* does it have a - on it            */
#define	T_BAR		0x0004		/* does it have a | on it            */
#define	T_BORDER	0x0008		/* does it have a border             */
#define	T_DIAMOND	0x0010		/* does it have a diamond on it      */
#define	T_X		0x0020		/* has it got an X on it             */
#define	T_POLE		0x0040		/* is it supported by a thin pole    */
#define	T_SOLID		0x0080		/* does it have a drape              */
#define	T_HANGS		0x0100		/* does it hang from above           */
#define	T_SET		0x0200		/* has it been set with a small sqr  */
#define	T_SETABLE	0x0400		/* can it be set                     */

#define	T_ARROW_LEFT	0x1000
#define	T_ARROW_RIGHT	0x2000
#define	T_ARROW_UP	0x4000
#define	T_ARROW_DOWN	0x8000

#define	TD_BLOWER	(T_MINUS|T_BAR|T_DIAMOND)
#define	TD_CROSS	(T_MINUS|T_BAR)

typedef struct sqr_struct
	{
	int	sqr_type;
	int	sqr_y;
	char	sqr_num;
	} SQR;

#define	SQR_ARRAY_X_SZ	(SCN_ARRAY_X_SZ * SQR_PER_SCN)
#define	SQR_ARRAY_Z_SZ	(SCN_ARRAY_Z_SZ * SQR_PER_SCN)

static SQR sqrs [SQR_ARRAY_X_SZ][SQR_ARRAY_Z_SZ];

static int teleports [256];

static void do_sqr(int x, int z, int ix, int iz)
	{
	int	type = 0, y = 80;
	int	i, j;
	char	*p;
	char	num = 255;

	for ( i = 0; i < 4; i++ )
		for ( j = 0; j < 4; j++ )
			switch ( block [iz + j + 1][ix + i + 1] )
				{
				case '.':	type |= T_VISIBLE;	break;
				case '-':	type |= T_MINUS;	break;
				case '|':	type |= T_BAR;		break;
				case 'R':	type |= T_BORDER;	break;
				case 'D':	type |= T_DIAMOND;
						p = &(block [iz + j + 1][ix + i + 2]);
						if ( isdigit(*p) )
							{
							num = atoi(p);
							teleports [num]++;
							}
						else
							{
							fprintf(stderr, "warning: undefined teleport number at (%d,%d)\n",
								x, z);
							num = 255;
							}
									break;
				case 'X':	type |= T_X;		break;
				case 'P':	type |= T_POLE;		break;
				case 'B':	type |= T_SOLID;	break;
				case 'H':	type |= T_HANGS;	break;
				case 'S':	type |= T_SET;		break;
				case 's':	type |= T_SETABLE;	break;
				case '<':	type |= T_ARROW_LEFT;	break;
				case '>':	type |= T_ARROW_RIGHT;	break;
				case '^':	type |= T_ARROW_UP;	break;
				case 'v':	type |= T_ARROW_DOWN;	break;
				case '*':	type |= TD_BLOWER;	break;
				case '+':	type |= TD_CROSS;	break;
				}

	switch ( block [iz + 4][ix + 1] )
		{
		case '0':	y = 20;			break;
		case '1':	y = 30;			break;
		case '2':	y = 40;			break;
		case '3':	y = 50;			break;
		case '4':	y = 60;			break;
		case '5':	y = 70;			break;
		case '6':	y = 80;			break;
		}

	if ( (type & (T_SOLID|T_POLE)) == (T_SOLID|T_POLE) )
		fatal("square at (%d,%d) has both support pole and solid body",
			x, z);
	sqrs [x][z].sqr_type = type;
	sqrs [x][z].sqr_y    = y;
	sqrs [x][z].sqr_num  = num;
	}

static void compile_scn(int scn_x, int scn_z, int sx, int sz)
	{
	int x, z, c, i;
	int bx, bz, bbx, bbz;

	bx = scn_x * SQR_PER_SCN;
	bz = scn_z * SQR_PER_SCN;
	bbx = 25 * sx;
	bbz = 25 * sz;

	/* consider stuff relevant to whole screen */
	
	for ( i = 0; i < BT_MAX; i++ )
		{
		c = block [bbz + 25][bbx + 1 + i];
		if ( isdigit(c) )
			scns [scn_x][scn_z].scn_n_bastards [i] = c - '0';
		else
			scns [scn_x][scn_z].scn_n_bastards [i] = 0;
		}


	c = block [bbz + 25][bbx + 24];
	if ( isdigit(c) )
		scns [scn_x][scn_z].scn_palette = c - '0';
	else
		scns [scn_x][scn_z].scn_palette = 0;

	scns [scn_x][scn_z].scn_visited = FALSE;

	/* now do its component squares */

	for ( x = 0; x < SQR_PER_SCN; x++ )
		for ( z = 0; z < SQR_PER_SCN; z++ )
			do_sqr(bx + x, bz + z, bbx + x * 5, bbz + z * 5);
	}

static void compile_block(int base_x, int base_z)
	{
	int sx, sz;

	for ( sx = 0; sx < 3; sx++ )
		for ( sz = 0; sz < 3; sz++ )
			compile_scn(base_x * 3 + sx, base_z * 3 + sz, sx, sz);
	}

int main(int argc, char *argv[])
	{
	int x, z, i, j;

	if ( argc != 2 )
		usage();

	trunc(argv [1]);
	if ( (fp = fopen(suffix(fn, argv [1], "cm"), "wb")) == NULL )
		fatal("can't open %s for reading", argv [1]);

	for ( x = 0; x < SQR_ARRAY_X_SZ; x++ )
		for ( z = 0; z < SQR_ARRAY_Z_SZ; z++ )
			for ( i = 0; i <= 4; i++ )
				{
				sqrs [x][z].sqr_type = T_VISIBLE|TD_BLOWER;
				sqrs [x][z].sqr_y    = 80;
				}

	for ( i = 0; i < 256; i++ )
		teleports [i] = 0;

	while ( get_line() )
		/* will be another 3x3 block of screens to deal with */
		{
		sscanf(line, "%d %d", &x, &z);
		read_in_block();
		compile_block(x, z);	
		}

	j = 0;
	for ( i = 0; i < 256; i++ )
		{
		if ( teleports [i] != 0 && teleports [i] != 2 && teleports [i] != 3 )
			fprintf(stderr, "warning: teleport %d has %d portals\n",
				i, teleports [i]);
		if ( teleports [i] )
			j = i + 1;
		}

	printf("next free teleport %d\n", j);

	fwrite(sqrs, sizeof(sqrs), 1, fp);
	fwrite(scns, sizeof(scns), 1, fp);
	fclose(fp);

	return 0;
	}
